//file_server的测试客户端实现
#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include <thread>
#include "etcd.hpp"
#include "channel.hpp" 
#include "base.pb.h"
#include "file.pb.h"
#include "utils.hpp"
//日志类参数
DEFINE_bool(log_mod,false,"true为发布模式,false为调试模式");
DEFINE_string(log_file,"","发布模式下日志存储的文件");
DEFINE_int32(log_level,0,"要输出的日志等级");
//服务注册参数
DEFINE_string(etcd_host,"http://127.0.0.1:2379","服务注册中心地址");
DEFINE_string(basedir,"/service","服务查询的根目录");
DEFINE_string(file_service,"/service/file_service","当前实例名称");

zzy_mims::ServiceChannels::ChannelPtr channel;
std::string single_file_id;
std::vector<std::string> multi_file_id;
 
TEST(put_test,single_file)
{
    // 3.进行RPC调用
    ::zzy_mims::FileService_Stub stub(channel.get());
    ::zzy_mims::PutSingleFileReq  req;
    //填写服务请求需要的数据并进行服务调用 
    std::string body;
    ASSERT_TRUE(zzy_mims::readFile("./test_content",body));
    req.set_request_id("21");
    req.mutable_file_data()->set_file_name("test_content");
    req.mutable_file_data()->set_file_size(body.size());
    req.mutable_file_data()->set_file_content(body);

    // 因为如果需要用到异步调用的时候，异步调用可能会直接对cntl和rep进行释放，所以不能简单定义到栈上
    brpc::Controller *cntl = new brpc::Controller();
    ::zzy_mims::PutSingleFileRsp *resp = new ::zzy_mims::PutSingleFileRsp();
     stub.PutSingleFile(cntl,&req,resp,nullptr);//同步调用
    ASSERT_FALSE(cntl->Failed());
    ASSERT_TRUE(resp->success());
    ASSERT_EQ(resp->file_info().file_size(), body.size());
    ASSERT_EQ(resp->file_info().file_name(), "test_content");
    single_file_id = resp->file_info().file_id();
    LOG_DEBUG("测试put_single_file中,文件ID:{}成功\n",single_file_id);
    std::this_thread::sleep_for(chrono::seconds(2));
    delete cntl;
    delete resp;
}
TEST(put_test,multi_file) 
{
    // 3.进行RPC调用
    ::zzy_mims::FileService_Stub stub(channel.get());
    ::zzy_mims::PutMultiFileReq  req;
    
    //填写服务请求需要的数据并进行服务调用
    req.set_request_id("22");

    std::string body;
    std::string body2;
    ASSERT_TRUE(zzy_mims::readFile("./test_content",body));
    ASSERT_TRUE(zzy_mims::readFile("./test_content2",body2));
    auto file_data = req.add_file_data();
    file_data->set_file_name("test_content");
    file_data->set_file_size(body.size());
    file_data->set_file_content(body);

    file_data = req.add_file_data();
    file_data->set_file_name("test_content2");
    file_data->set_file_size(body2.size());
    file_data->set_file_content(body2);
    // 因为如果需要用到异步调用的时候，异步调用可能会直接对cntl和rep进行释放，所以不能简单定义到栈上
    brpc::Controller *cntl = new brpc::Controller();
    ::zzy_mims::PutMultiFileRsp *resp = new ::zzy_mims::PutMultiFileRsp();
     stub.PutMultiFile(cntl,&req,resp,nullptr);//同步调用
    ASSERT_FALSE(cntl->Failed());
    ASSERT_TRUE(resp->success());
    for(int i =0;i<2;i++)
    {
        multi_file_id.emplace_back(resp->file_info(i).file_id());
        LOG_DEBUG("测试put_single_file中,文件ID:{}成功\n",multi_file_id[i]);
    }
    std::this_thread::sleep_for(chrono::seconds(2));
    delete cntl;
    delete resp;
}
TEST(get_test,single_file)
{
    // 3.进行RPC调用
    ::zzy_mims::FileService_Stub stub(channel.get());
    ::zzy_mims::GetSingleFileReq  req;

    //填写服务请求需要的数据并进行服务调用
    req.set_request_id("23");
    req.set_file_id(single_file_id);

    // 因为如果需要用到异步调用的时候，异步调用可能会直接对cntl和rep进行释放，所以不能简单定义到栈上
    brpc::Controller *cntl = new brpc::Controller();
    ::zzy_mims::GetSingleFileRsp *resp = new ::zzy_mims::GetSingleFileRsp();
     stub.GetSingleFile(cntl,&req,resp,nullptr);//同步调用
    ASSERT_FALSE(cntl->Failed());
    ASSERT_TRUE(resp->success());
    ASSERT_EQ(resp->file_data().file_id(), single_file_id);
    zzy_mims::writeFile("test1",resp->file_data().file_content());

    std::this_thread::sleep_for(chrono::seconds(2));
    delete cntl;
    delete resp;
}
TEST(get_test,multi_file)
{
    // 3.进行RPC调用
    ::zzy_mims::FileService_Stub stub(channel.get());
    ::zzy_mims::GetMultiFileReq  req;

    //填写服务请求需要的数据并进行服务调用
    req.set_request_id("24");
    req.add_file_id_list(multi_file_id[0]);
    req.add_file_id_list(multi_file_id[1]);


    // 因为如果需要用到异步调用的时候，异步调用可能会直接对cntl和rep进行释放，所以不能简单定义到栈上
    brpc::Controller *cntl = new brpc::Controller();
    ::zzy_mims::GetMultiFileRsp *resp = new ::zzy_mims::GetMultiFileRsp();
     stub.GetMultiFile(cntl,&req,resp,nullptr);//同步调用
    ASSERT_FALSE(cntl->Failed());
    ASSERT_TRUE(resp->success());

    ASSERT_TRUE(resp->file_data().count(multi_file_id[0]));
    ASSERT_TRUE(resp->file_data().count(multi_file_id[1]));
    auto map = resp->file_data();//这里多使用个auto变量的原因是resp->file_data()返回的是右值，会在表达式后销毁，不能进行下一个表达式运算，所以在栈上用变量保存一下
    zzy_mims::writeFile("Mtest1",map[multi_file_id[0]].file_content());
    zzy_mims::writeFile("Mtest2",map[multi_file_id[1]].file_content());

    std::this_thread::sleep_for(chrono::seconds(2));
    delete cntl;
    delete resp;
}


int main(int argc,char* argv[])
{ 
    testing::InitGoogleTest(&argc, argv);
    google::ParseCommandLineFlags(&argc,&argv,true);
    zzy_mims::init_logger(FLAGS_log_mod,FLAGS_log_file,(spdlog::level::level_enum)FLAGS_log_level);
    //关闭brpc的默认日志输出
    logging::LoggingSettings logset;
    logset.logging_dest = logging::LoggingDestination::LOG_TO_NONE;
    logging::InitLogging(logset);
    //1.创建RPC信道管理对象
    auto scm = std::make_shared<zzy_mims::ServChanManager>();
    scm->Declared(FLAGS_file_service);
    //2.构建服务发现对象
    auto online = std::bind(&zzy_mims::ServChanManager::ServiceOnline,scm.get(),std::placeholders::_1,std::placeholders::_2);
    auto offline = std::bind(&zzy_mims::ServChanManager::ServiceOffline,scm.get(),std::placeholders::_1,std::placeholders::_2);
    std::shared_ptr<zzy_mims::Discovery> dclient = std::make_shared<zzy_mims::Discovery>(FLAGS_etcd_host,FLAGS_basedir,online,offline); 
    //获取信道
    channel = scm->choose(FLAGS_file_service);
    if(!channel)
    return -1;
    return RUN_ALL_TESTS();
}